﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using WhiteFlow.DevTrackingTool.Common.Contracts;
using WhiteFlow.Wpf.Controls.Common;
using System.Windows.Media.Imaging;

namespace WhiteFlow.DevTrackingTool.UI.Controls
{
    /// <summary>
    /// Represents a dialog that displays a message to the user, with some interactivity.
    /// </summary>
    [TemplateVisualState(Name = "Closed", GroupName = "CommonStates")]
    [TemplateVisualState(Name = "Open", GroupName = "CommonStates")]
    [TemplatePart(Name = "PART_Icon", Type = typeof(Bitmap))]
    [TemplatePart(Name = "PART_BtnOk", Type = typeof(Button))]
    [TemplatePart(Name = "PART_BtnYes", Type = typeof(Button))]
    [TemplatePart(Name = "PART_BtnNo", Type = typeof(Button))]
    [TemplatePart(Name = "PART_BtnCancel", Type = typeof(Button))]
    public class MessageDialog : Control, IMessageDialog
    {
        #region Constants

        public const string QuestionIconPropertyName = "QuestionIcon";

        public const string InformationIconPropertyName = "InformationIcon";

        public const string WarningIconPropertyName = "WarningIcon";

        public const string ErrorIconPropertyName = "ErrorIcon";

        public const string TitlePropertyName = "Title";

        public const string MessagePropertyName = "Message";

        public const string IsClosedPropertyName = "IsClosed";

        #endregion

        #region Fields

        private Bitmap PART_Icon;

        private Button PART_BtnOk;

        private Button PART_BtnYes;

        private Button PART_BtnNo;

        private Button PART_BtnCancel;

        private Action<MessageBoxResult> callback;

        private CancelEventArgs cancelEventArgs;

        #endregion

        #region DependencyProperties Declaration

        public static readonly DependencyProperty QuestionIconProperty;

        public static readonly DependencyProperty InformationIconProperty;

        public static readonly DependencyProperty WarningIconProperty;

        public static readonly DependencyProperty ErrorIconProperty;
        
        public static readonly DependencyProperty TitleProperty;
        
        public static readonly DependencyProperty MessageProperty;

        public static readonly DependencyProperty IsClosedProperty;

        #endregion

        #region Properties

        public BitmapSource QuestionIcon
        {
            get { return GetValue(QuestionIconProperty) as BitmapSource; }
            set { SetValue(QuestionIconProperty, value); }
        }

        public BitmapSource InformationIcon
        {
            get { return GetValue(InformationIconProperty) as BitmapSource; }
            set { SetValue(InformationIconProperty, value); }
        }

        public BitmapSource WarningIcon
        {
            get { return GetValue(WarningIconProperty) as BitmapSource; }
            set { SetValue(WarningIconProperty, value); }
        }

        public BitmapSource ErrorIcon
        {
            get { return GetValue(ErrorIconProperty) as BitmapSource; }
            set { SetValue(ErrorIconProperty, value); }
        }

        /// <summary>
        /// Gets or sets the title for this message box.
        /// </summary>
        /// <value>
        /// The title for this message box.
        /// </value>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        /// Gets or sets the message displayed by this message box.
        /// </summary>
        /// <value>
        /// The message displayed by this message box.
        /// </value>
        public string Message
        {
            get { return (string)GetValue(MessageProperty); }
            set { SetValue(MessageProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this message box is closed.
        /// </summary>
        /// <value>
        /// <c>true</c> if this message box is closed, <c>false</c> otherwise.
        /// </value>
        public bool IsClosed
        {
            get { return (bool)GetValue(IsClosedProperty); }
            set { SetValue(IsClosedProperty, value); }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes the <see cref="MessageDialog"/> class.
        /// </summary>
        static MessageDialog()
        {
            #region DependencyProperties Registration

            QuestionIconProperty = DependencyProperty.Register(
                QuestionIconPropertyName,
                typeof(BitmapSource),
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(null));

            InformationIconProperty = DependencyProperty.Register(
                InformationIconPropertyName,
                typeof(BitmapSource),
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(null));

            WarningIconProperty = DependencyProperty.Register(
                WarningIconPropertyName,
                typeof(BitmapSource),
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(null));

            ErrorIconProperty = DependencyProperty.Register(
                ErrorIconPropertyName,
                typeof(BitmapSource),
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(null));

            TitleProperty = DependencyProperty.Register(
                TitlePropertyName,
                typeof(string),
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(null));

            MessageProperty = DependencyProperty.Register(
                MessagePropertyName,
                typeof(string),
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(null));

            IsClosedProperty = DependencyProperty.Register(
                IsClosedPropertyName,
                typeof(bool),
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(true));

            #endregion

            #region Template Application

            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(MessageDialog),
                new FrameworkPropertyMetadata(typeof(MessageDialog)));

            #endregion
        }

        #endregion

        #region Override Methods

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            PART_Icon = this.GetTemplateChild("PART_Icon") as Bitmap;
            
            PART_BtnOk = this.GetTemplateChild("PART_BtnOk") as Button;
            PART_BtnYes = this.GetTemplateChild("PART_BtnYes") as Button;
            PART_BtnNo = this.GetTemplateChild("PART_BtnNo") as Button;
            PART_BtnCancel = this.GetTemplateChild("PART_BtnCancel") as Button;

            PART_BtnOk.Click += new RoutedEventHandler(OnDialogButtonClick);
            PART_BtnYes.Click += new RoutedEventHandler(OnDialogButtonClick);
            PART_BtnNo.Click += new RoutedEventHandler(OnDialogButtonClick);
            PART_BtnCancel.Click += new RoutedEventHandler(OnDialogButtonClick);

            VisualStateManager.GoToState(this, "Closed", false);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Called when one of the available buttons in the current dialog is clicked.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        protected void OnDialogButtonClick(object sender, RoutedEventArgs e)
        {
            VisualStateManager.GoToState(this, "Closed", false);
            IsClosed = true;

            if (sender == PART_BtnOk)
            {
                if (callback != null)
                    callback(MessageBoxResult.OK);
            }
            else if (sender == PART_BtnYes)
            {
                if (callback != null)
                    callback(MessageBoxResult.Yes);
            }
            else if (sender == PART_BtnNo)
            {
                if (callback != null)
                    callback(MessageBoxResult.No);
            }
            else if (sender == PART_BtnCancel)
            {
                if (cancelEventArgs != null)
                    cancelEventArgs.Cancel = true;

                if (callback != null)
                    callback(MessageBoxResult.Cancel);
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Opens the dialog and shows the specified message to the user.
        /// </summary>
        /// <param name="message">The message to display.</param>
        /// <param name="title">The title.</param>
        /// <param name="callback">The callback to execute when the user has made his choice.</param>
        /// <param name="buttons">The buttons to make available in the dialog.</param>
        /// <param name="image">The image to display next to the message.</param>
        /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
        public void ShowMessage(string message, string title, Action<MessageBoxResult> callback, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxImage image = MessageBoxImage.None, CancelEventArgs e = null)
        {
            Title = title;
            Message = message;
            this.callback = callback;
            this.cancelEventArgs = e;

            HideAllDialogButtons();

            PART_Icon.Source = null;
            PART_Icon.Update();
            
            bool isIconSet = true;
            
            switch (image)
            {
                case MessageBoxImage.Question:
                    PART_Icon.Source = QuestionIcon;
                    break;
                case MessageBoxImage.Information:
                    PART_Icon.Source = InformationIcon;
                    break;
                case MessageBoxImage.Warning:
                    PART_Icon.Source = WarningIcon;
                    break;
                case MessageBoxImage.Error:
                    PART_Icon.Source = ErrorIcon;
                    break;
                default:
                    isIconSet = false;
                    break;
            }

            if (isIconSet) PART_Icon.Update();

            switch (buttons)
            {
                case MessageBoxButton.OK:
                    PART_BtnOk.Visibility = System.Windows.Visibility.Visible;
                    break;
                case MessageBoxButton.OKCancel:
                    PART_BtnOk.Visibility = System.Windows.Visibility.Visible;
                    PART_BtnCancel.Visibility = System.Windows.Visibility.Visible;
                    break;
                case MessageBoxButton.YesNo:
                    PART_BtnYes.Visibility = System.Windows.Visibility.Visible;
                    PART_BtnNo.Visibility = System.Windows.Visibility.Visible;
                    break;
                case MessageBoxButton.YesNoCancel:
                    PART_BtnYes.Visibility = System.Windows.Visibility.Visible;
                    PART_BtnNo.Visibility = System.Windows.Visibility.Visible;
                    PART_BtnCancel.Visibility = System.Windows.Visibility.Visible;
                    break;
            }

            VisualStateManager.GoToState(this, "Open", false);
            IsClosed = false;
        }

        #endregion

        #region Private Methods

        private void HideAllDialogButtons()
        {
            PART_BtnOk.Visibility = System.Windows.Visibility.Collapsed;
            PART_BtnYes.Visibility = System.Windows.Visibility.Collapsed;
            PART_BtnNo.Visibility = System.Windows.Visibility.Collapsed;
            PART_BtnCancel.Visibility = System.Windows.Visibility.Collapsed;
        }

        #endregion
    }
}